
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct Cubes {
    red: i32,
    green: i32,
    blue: i32,
}

impl From<&str> for Cubes {
    fn from(value: &str) -> Self {
        let mut red: i32 = 0;
        let mut green: i32 = 0;
        let mut blue: i32 = 0;

        let convertor = |s: &str| -> i32 {
            let pos = s.find(|c | c != ' ').unwrap();
            s[pos..].parse().unwrap()
        };

        value.split(",").for_each( |token: &str| {
            if let Some(pos) = token.find("red") {
                red = convertor(&token[..(pos - 1)]);
            }
            if let Some(pos) = token.find("green") {
                green = convertor(&token[..(pos - 1)]);
            }
            if let Some(pos) = token.find("blue") {
                blue = convertor(&token[..(pos - 1)]);
            }
        });

        Self { red, green, blue }
    }
}

#[derive(PartialEq, Debug)]
pub struct Game {
    id: i32,
    cubes_set: Vec<Cubes>,
}

impl Game {
    pub fn powers(&self) -> i32 {    
        let max_red = self.cubes_set.iter().map(|cubes| cubes.red ).max().unwrap();
        let max_green = self.cubes_set.iter().map(|cubes| cubes.green ).max().unwrap();
        let max_blue = self.cubes_set.iter().map(|cubes| cubes.blue ).max().unwrap();

        max_red * max_blue * max_green
    }
}

impl From<&str> for Game {
    fn from(value: &str) -> Self {
        let colon_pos = value.find(":").expect("Can't convert to Game.");

        let id_str = &value[5..colon_pos];
        let cubes_set_str = &value[colon_pos + 1..];

        let id: i32 = id_str.parse().expect("Can't convert to id.");

        let cubes_set: Vec<Cubes> = cubes_set_str.split(";").map(|s| s.into()).collect();

        Self { id, cubes_set }
    }
}

#[cfg(test)]
mod test {
    use super::{Cubes, Game};

    #[test]
    fn str_to_cubes() {
        let cubes: Cubes = " 1 red, 2 green, 6 blue".into();
        assert_eq!(cubes, Cubes{red: 1, green: 2, blue: 6});
    }

    #[test]
    fn str_to_game() {
        let game: Game = "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green".into();
        assert_eq!(
            game, 
            Game { 
                id: 1,
                cubes_set: vec![
                    Cubes{red: 4, green: 0, blue: 3},
                    Cubes{red: 1, green: 2, blue: 6},
                    Cubes{red: 0, green: 2, blue: 0}
            ] }
        );
    }
}